Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replays - Install missing map #13233

Merged
merged 3 commits into from May 14, 2017
Merged

Replays - Install missing map #13233

merged 3 commits into from May 14, 2017

Conversation

rob-v
Copy link
Contributor

@rob-v rob-v commented May 3, 2017

Replay's Map preview unification with Lobby map preview - Install map, map author, map title tooltip, ...

obrazok

Closes #11149.

pchote
pchote previously requested changes May 6, 2017
Copy link
Member

@pchote pchote left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The overall approach here looks good, and naturally extends towards our wishlist goal of showing players and spawns in the server list map previews. I haven't looked at the replay part of this in any detail yet, but here's some issues with the map preview logic to start with.

Please also split this into separate commits for refactoring (changing LobbyMapPreviewLogic to work from additional places) vs new features (making the ReplayBrowserLogic use it). This makes it much easier to understand changes when looking back through the git history.

m => WidgetUtils.TruncateText("Created by {0}".F(lobby.Map.Author), authorLabel.Bounds.Width, font));
authorLabel.GetText = () => author.Update(lobby.Map);
}
available.IsVisible = () => getMap().Status == MapStatus.Available && (!getMap().RulesLoaded || !getMap().InvalidCustomRules);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our map handling code and parts of our UI are multithreaded, so seeing lines like this makes me uneasy.

We knew from the design of LobbyLogic that lobby.Map would not change between evaluating e.g. lobby.Map.Status andlobby.Map.RulesLoaded, but we don't have that guarantee for arbitrary getMaps.

Please change these to query getMap() once per evaluation, e.g. here:

available.IsVisible = () => 
{
	var map = getMap();
	return map.Status == MapStatus.Available && (!map.RulesLoaded || !map.InvalidCustomRules);
};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The natural question that follows this is whether we can cache getMap across the different widget bindings. The answer is probably, but it is probably not worth it. You could in principle override the ChromeLogic.Tick and then set a field in the class that is used in all the bindings, but I expect that this would introduce a noticable latency, and possibly other side effects.

So long as the map usage is consistent within individual bindings, it's generally not a big deal if it changes between evaluating different widgets. The worst case scenario is that e.g. the title and author labels are out of sync for 1/60th of a second until the next frame is rendered.


var install = download.GetOrNull<ButtonWidget>("MAP_INSTALL");
if (install != null)
{
install.OnClick = () => lobby.Map.Install(mapRepository, () =>
install.OnClick = () => getMap().Install(mapRepository, () =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good example of the getMap() danger: it generally takes between half and a few seconds to install a map, and its quite possible for the host to change map between getMap().Install and getMap().PreloadRules running.

The fix again is to evaluate it once to be certain that it can't change under you:

install.OnClick = () => 
{
	var map = getMap();
	map.Install(mapRepository, () =>
	{
		map.PreloadRules();
		if (orderManager != null)
			Game.RunAfterTick(() => orderManager.IssueOrder(Order.Command("state {0}".F(Session.ClientState.NotReady))));
	}
};

@@ -22,100 +24,39 @@ public class LobbyMapPreviewLogic : ChromeLogic
int blinkTick;

[ObjectCreator.UseCtor]
internal LobbyMapPreviewLogic(Widget widget, ModData modData, OrderManager orderManager, LobbyLogic lobby)
internal LobbyMapPreviewLogic(Widget widget, ModData modData, OrderManager orderManager, Func<MapPreview> getMap,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer Lobby specific, so the class and file should be renamed.

@@ -27,24 +27,28 @@ public class ReplayBrowserLogic : ChromeLogic
{
static Filter filter = new Filter();

public MapPreview Map { get; private set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't need to be public?


if (replay == null)
return;

try
{
if (Map.Status != MapStatus.Available)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit: don't leave hanging blocks. The hanging else-if is ambiguous between the inner if and the outer if (with an indentation error), so this needs braces to make it explicit.

@rob-v
Copy link
Contributor Author

rob-v commented May 6, 2017

Updated.

Copy link
Member

@chrisforbes chrisforbes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nits, but I like it.


MapPreview Map { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a property at all, if you're making both accessors private?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LobbyLogic.Map was used in LobbyUtils so public get. I pass now Map instead of LobbyLogic so public was removed. I'll change it to field.


Dictionary<CPos, SpawnOccupant> selectedSpawns;
MapPreview Map { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, may as well just be a field here.

@rob-v
Copy link
Contributor Author

rob-v commented May 13, 2017

Updated - property Map replaced by field.

Copy link
Member

@pchote pchote left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks for taking this feature on. 👍 after a few small tweaks:

var map = getMap();
return map.Status == MapStatus.Available && (!map.RulesLoaded || !map.InvalidCustomRules);
};
SetupWidgets(available, getMap, onMouseDown, getSpawnOccupants);
Copy link
Member

@pchote pchote May 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit: newline between closing braces and the next statement.

var map = getMap();
return map.Status == MapStatus.Available && map.InvalidCustomRules;
};
SetupWidgets(invalid, getMap, onMouseDown, getSpawnOccupants);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here too.

var map = getMap();
return map.Status != MapStatus.Available && map.Status != MapStatus.DownloadAvailable;
};
SetupWidgets(progress, getMap, onMouseDown, getSpawnOccupants);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here too.

statusSearching.IsVisible = () => getMap().Status == MapStatus.Searching;

var statusUnavailable = progress.GetOrNull("MAP_STATUS_UNAVAILABLE");
if (statusUnavailable != null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit: put braces around hanging blocks.

{ "getMap", (Func<MapPreview>)(() => Map) },
{ "onMouseDown", (Action<MapPreviewWidget, MapPreview, MouseInput>)((preview, map, mi) => { }) },
{ "getSpawnOccupants", (Func<MapPreview, Dictionary<CPos, SpawnOccupant>>)(map => LobbyUtils.GetSpawnOccupants(selectedReplay.GameInfo.Players, map)) },
});

panel.Get<LabelWidget>("DURATION").GetText = () => WidgetUtils.FormatTimeSeconds((int)selectedReplay.GameInfo.Duration.TotalSeconds);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please change this to the following while you're here?

var replayDuration = new CachedTransform<ReplayMetadata, string>(r =>
	"Duration: {0}".F(WidgetUtils.FormatTimeSeconds((int)selectedReplay.GameInfo.Duration.TotalSeconds)));
panel.Get<LabelWidget>("DURATION").GetText = () => replayDuration.Update(selectedReplay);

This makes the label look less disconnected when the install map button is showing, plus a small perf win.

selectedSpawns = (selectedReplay != null)
? LobbyUtils.GetSpawnOccupants(selectedReplay.GameInfo.Players, selectedReplay.GameInfo.MapPreview)
: new Dictionary<CPos, SpawnOccupant>();
map = (selectedReplay != null) ? selectedReplay.GameInfo.MapPreview : MapCache.UnknownMap;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit: unnecessary parenthesis around selectedReplay != null.

@rob-v
Copy link
Contributor Author

rob-v commented May 14, 2017

Updated.

@pchote pchote merged commit 127ef8b into OpenRA:bleed May 14, 2017
@LipkeGu
Copy link
Member

LipkeGu commented May 17, 2017

Can anyone agree that the PR is getting compiled .... i get errors like "local variable map is already define and gets overwritten"

@reaperrr
Copy link
Contributor

i get errors like "local variable map is already define and gets overwritten"

Same here, the last commit is to blame. Needs to be reverted or fixed.

@rob-v
Copy link
Contributor Author

rob-v commented May 17, 2017

The PR before merge was built succesfully (also locally). There is simple fix to avoid this 'warning as error'. Could you please review quickly #13071? It by chance removes the local 'map' argument so solves this issue.

@reaperrr
Copy link
Contributor

#13071 reduces the errors, but lines 387 and 401 in LobbyLogic still have that issue there.

@pchote
Copy link
Member

pchote commented May 17, 2017

This should be fixed as its own PR, separate to adding any new features.

@rob-v
Copy link
Contributor Author

rob-v commented May 17, 2017

#13071 Updated - map parameter renamed, compiled now with the same MSBuild, so should be fine now.

@rob-v
Copy link
Contributor Author

rob-v commented May 17, 2017

Fixed by #13313.

@rob-v rob-v deleted the ReplayInstallMap branch May 18, 2017 07:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants